package com.mademoisellegeek.carrentalsimulation.txt;

import com.mademoisellegeek.carrentalsimulation.CarRentalException;
import com.mademoisellegeek.carrentalsimulation.enums.CarRentalExceptionType;
import com.mademoisellegeek.carrentalsimulation.CarRentalSimulationApp;
import com.mademoisellegeek.carrentalsimulation.Utils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;

public class DocumentGenerator {

    /** 
     * 1 to 3 garages per town
     * 10 to 50 spaces per garage
     * 
     * Format of each entry:
     * garageId, Town, numberOfSpaces
     * 1,PARIS,14
     */
    public int generateGarageList(Map<String, Integer> towns) throws CarRentalException {
        int id = 1;
        String garages = "";
        for (String town : towns.keySet()) {
            int nbGarages = randomInt(1, 3);
            for (int i = 0; i < nbGarages; i++) {
                garages += id + CarRentalSimulationApp.SEPARATOR + town + 
                           CarRentalSimulationApp.SEPARATOR + randomInt(10, 50) + 
                           CarRentalSimulationApp.NEWLINE;
                id++;
            }
        }
        setContents(CarRentalSimulationApp.GARAGES, garages);
        return id;
    }

    public void generateVehicleList(int nbGarages, int nbVehicles) throws CarRentalException {
        String vehicles = "";
        for (int id = 1; id < nbVehicles + 1; id++) {
            vehicles += id + CarRentalSimulationApp.SEPARATOR + randomInt(1, nbGarages) + CarRentalSimulationApp.NEWLINE;
        }
        setContents(CarRentalSimulationApp.VEHICLES, vehicles);
    }

    public void generateRequestList(int minNbDays, Map<String, Integer> towns) throws CarRentalException {
        String requests = "";
        int days = 0;
        int id = 1;
        while (days < minNbDays) {
            int randomStartDate = randomInt(1, 364);
            int randomEndDate = randomStartDate + randomInt(1, 20);
            if (randomEndDate > 365) {
                randomEndDate = 365;
            }
            requests += id
                    + CarRentalSimulationApp.SEPARATOR
                    + getRandomTown(towns)
                    + CarRentalSimulationApp.SEPARATOR
                    + getRandomTown(towns)
                    + CarRentalSimulationApp.SEPARATOR
                    + randomStartDate
                    + CarRentalSimulationApp.SEPARATOR
                    + randomEndDate
                    + CarRentalSimulationApp.NEWLINE;
            days += randomEndDate - randomStartDate + 1;
            id++;
        }
        setContents(CarRentalSimulationApp.REQUESTS, requests);
    }

    /*
     * Utilities
     */
    private static void setContents(String fileName, String aContents) throws CarRentalException {
        File file = new File(fileName + CarRentalSimulationApp.TXT_EXTENSION);
        if (file == null) {
            throw new IllegalArgumentException("File should not be null.");
        }
        if (!file.exists()) {
            throw new CarRentalException("File does not exist: " + file, CarRentalExceptionType.FILE_GENERATOR);
        }
        if (!file.isFile()) {
            throw new CarRentalException("Should not be a directory: " + file, CarRentalExceptionType.FILE_GENERATOR);
        }
        if (!file.canWrite()) {
            throw new CarRentalException("File cannot be written: " + file, CarRentalExceptionType.FILE_GENERATOR);
        }

        try {
            BufferedWriter output = new BufferedWriter(new FileWriter(file));
            output.write(aContents);
            output.close();
        } catch (IOException e) {
            throw new CarRentalException(fileName, CarRentalExceptionType.FILE_GENERATOR);
        }
    }

    private int randomInt(int lower, int higher) {
        return (int) (Math.random() * (higher - lower + 1)) + lower;
    }

    private String getRandomTown(Map<String, Integer> towns) {
        int index = randomInt(1, towns.size());
        Map<Integer, String> invertedTowns = Utils.invert(towns);
        return invertedTowns.get(index);
    }
}
